package com.ctsi.commons.util.database;

import com.ctsi.commons.util.UtilValidate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.Serializable;
import java.sql.*;
import java.util.*;

/**
 * 获取数据库基本信息，主要是表相关信息
 * 
 * @author yueming
 * 
 */
public class DatabaseUtil {
	private static final Logger log = LoggerFactory.getLogger(DatabaseUtil.class);

	private Connection connection;

	private String schemaName;

	public DatabaseUtil() {
		super();

	}

	public DatabaseUtil(Connection connection, String schemaName) {
		super();
		this.connection = connection;

		this.schemaName = schemaName;
	}

	public String getSchemaName() {
		return schemaName;
	}

	public void setSchemaName(String schemaName) {
		this.schemaName = schemaName;
	}

	public String getSchemaName(DatabaseMetaData dbData) throws SQLException {
		if (dbData.supportsSchemasInTableDefinitions()) {
			if (this.schemaName != null && this.schemaName.length() > 0) {
				return this.schemaName;
			} else {
				return dbData.getUserName();
			}
		}
		return null;
	}

	public String getTransactionIsolation(int level) {
		if (level == Connection.TRANSACTION_READ_COMMITTED)
			return "TRANSACTION_READ_COMMITTED";
		if (level == Connection.TRANSACTION_READ_UNCOMMITTED)
			return "TRANSACTION_READ_UNCOMMITTED";
		if (level == Connection.TRANSACTION_REPEATABLE_READ)
			return "TRANSACTION_REPEATABLE_READ";
		if (level == Connection.TRANSACTION_SERIALIZABLE)
			return "TRANSACTION_SERIALIZABLE";
		if (level == Connection.TRANSACTION_NONE)
			return "TRANSACTION_NONE";
		else
			return "unknown:" + level;
	}

	/**
	 * db与jdbc基本信息
	 * 
	 * @param dbData
	 */
	public void printDbMiscData(DatabaseMetaData dbData) {
		if (dbData == null) {
			return;
		}
		if (log.isInfoEnabled()) {
			try {
				log.info("Database Product Name is " + dbData.getDatabaseProductName());
				log.info("Database Product Version is " + dbData.getDatabaseProductVersion());
				log.info("Database Driver Name is " + dbData.getDriverName());
				log.info("Database Driver Version is " + dbData.getDriverVersion());
				log.info("Database Driver JDBC Version is " + dbData.getJDBCMajorVersion() + "." + dbData.getJDBCMinorVersion());
			} catch (SQLException sqle) {
				log.warn("Unable to get Driver name & version information");
			} catch (AbstractMethodError ame) {
				log.warn("Unable to get Driver JDBC Version");
			}
		}
		// Db/Driver support settings
		if (log.isInfoEnabled()) {
			try {

				log.info("- supports transactions    [" + dbData.supportsTransactions() + "]*");
				log.info("- isolation None           [" + dbData.supportsTransactionIsolationLevel(Connection.TRANSACTION_NONE) + "]");
				log.info("- isolation ReadCommitted  [" + dbData.supportsTransactionIsolationLevel(Connection.TRANSACTION_READ_COMMITTED) + "]");
				log.info("- isolation ReadUncommitted[" + dbData.supportsTransactionIsolationLevel(Connection.TRANSACTION_READ_UNCOMMITTED) + "]");
				log.info("- isolation RepeatableRead [" + dbData.supportsTransactionIsolationLevel(Connection.TRANSACTION_REPEATABLE_READ) + "]");
				log.info("- default  Isolation       [" + getTransactionIsolation(dbData.getDefaultTransactionIsolation()) + "]");

				log.info("- isolation Serializable   [" + dbData.supportsTransactionIsolationLevel(Connection.TRANSACTION_SERIALIZABLE) + "]");
				Statement sta = getConnection().createStatement();
				log.info("- default fetchsize        [" + sta.getFetchSize() + "]");
				sta.close();

				log.info("- forward only type        [" + dbData.supportsResultSetType(ResultSet.TYPE_FORWARD_ONLY) + "]");
				log.info("- scroll sensitive type    [" + dbData.supportsResultSetType(ResultSet.TYPE_SCROLL_SENSITIVE) + "]");
				log.info("- scroll insensitive type  [" + dbData.supportsResultSetType(ResultSet.TYPE_SCROLL_INSENSITIVE) + "]");
				log.info("- is case sensitive        [" + dbData.supportsMixedCaseIdentifiers() + "]");
				log.info("- stores LowerCase         [" + dbData.storesLowerCaseIdentifiers() + "]");
				log.info("- stores MixedCase         [" + dbData.storesMixedCaseIdentifiers() + "]");
				log.info("- stores UpperCase         [" + dbData.storesUpperCaseIdentifiers() + "]");
				log.info("- max table name length    [" + dbData.getMaxTableNameLength() + "]");
				log.info("- max column name length   [" + dbData.getMaxColumnNameLength() + "]");
				log.info("- max schema name length   [" + dbData.getMaxSchemaNameLength() + "]");
				log.info("- max column in table      [" + dbData.getMaxColumnsInTable() + "]");
				log.info("- concurrent connections   [" + dbData.getMaxConnections() + "]");
				log.info("- concurrent statements    [" + dbData.getMaxStatements() + "]");
				log.info("- ANSI SQL92 Entry         [" + dbData.supportsANSI92EntryLevelSQL() + "]");
				log.info("- ANSI SQL92 Itermediate   [" + dbData.supportsANSI92IntermediateSQL() + "]");
				log.info("- ANSI SQL92 Full          [" + dbData.supportsANSI92FullSQL() + "]");
				log.info("- ODBC SQL Grammar Core    [" + dbData.supportsCoreSQLGrammar() + "]");
				log.info("- ODBC SQL Grammar Extended[" + dbData.supportsExtendedSQLGrammar() + "]");
				log.info("- ODBC SQL Grammar Minimum [" + dbData.supportsMinimumSQLGrammar() + "]");
				log.info("- outer joins              [" + dbData.supportsOuterJoins() + "]*");
				log.info("- limited outer joins      [" + dbData.supportsLimitedOuterJoins() + "]");
				log.info("- full outer joins         [" + dbData.supportsFullOuterJoins() + "]");
				log.info("- group by                 [" + dbData.supportsGroupBy() + "]");
				log.info("- group by not in select   [" + dbData.supportsGroupByUnrelated() + "]");
				log.info("- column aliasing          [" + dbData.supportsColumnAliasing() + "]");
				log.info("- order by not in select   [" + dbData.supportsOrderByUnrelated() + "]");

				log.info("- alter table add column   [" + dbData.supportsAlterTableWithAddColumn() + "]*");
				log.info("- alter table drop column  [" + dbData.supportsAlterTableWithDropColumn() + "]*");
				log.info("- non-nullable column      [" + dbData.supportsNonNullableColumns() + "]");

			} catch (Exception e) {
				log.warn("error:{}", e);
			}
		}
	}

	public TreeSet<String> getTableNames(boolean appendSchemaName) {
		return getTableNames(appendSchemaName, false);
	}

	/**
	 * 
	 * @param appendSchemaName
	 *            表明成前是否增加schema name true增加 false不增加
	 * @return
	 */
	public TreeSet<String> getTableNames(boolean appendSchemaName, boolean onlyTable) {

		DatabaseMetaData dbData = this.getDatabaseMetaData();
		if (dbData == null) {
			return null;
		}

		TreeSet<String> tableNames = new TreeSet<String>();
		ResultSet tableSet = null;

		String lookupSchemaName = null;
		try {
			String[] types;
			if (onlyTable) {
				types = new String[1];
				types[0] = "TABLE";
			} else {
				types = new String[4];
				types[0] = "TABLE";
				types[1] = "VIEW";
				types[2] = "ALIAS";
				types[3] = "SYNONYM";
			}

			lookupSchemaName = getSchemaName(dbData);
			tableSet = dbData.getTables(null, lookupSchemaName, null, types);
			if (tableSet == null) {
				log.warn("getTables returned null set");
				return tableNames;
			}
		} catch (SQLException sqle) {
			String message = "Unable to get list of table information, let's try the create anyway... Error was:" + sqle.toString();
			log.error(message);
			throw new RuntimeException(message);

		}

		try {
			boolean needsUpperCase = false;
			try {
				needsUpperCase = dbData.storesLowerCaseIdentifiers() || dbData.storesMixedCaseIdentifiers();
			} catch (SQLException sqle) {
				String message = "Error getting identifier case information... Error was:" + sqle.toString();
				log.error(message);
				throw new RuntimeException(message);
			}
			while (tableSet.next()) {
				try {
					String tableName = tableSet.getString("TABLE_NAME");

					if (needsUpperCase && tableName != null) {
						tableName = tableName.toUpperCase();
					}
					if (appendSchemaName && lookupSchemaName != null) {
						tableName = lookupSchemaName + "." + tableName;
					}

					String tableType = tableSet.getString("TABLE_TYPE");
					// 需要的类型
					if (tableType != null && !"TABLE".equalsIgnoreCase(tableType) && !"VIEW".equalsIgnoreCase(tableType) && !"ALIAS".equalsIgnoreCase(tableType) && !"SYNONYM".equalsIgnoreCase(tableType)) {
						continue;
					}

					tableNames.add(tableName);

				} catch (SQLException sqle) {
					String message = "Error getting table information... Error was:" + sqle.toString();
					log.error(message);
					continue;
				}
			}
		} catch (SQLException sqle) {
			String message = "Error getting next table information... Error was:" + sqle.toString();
			log.error(message);
			throw new RuntimeException(message);
		} finally {
			try {
				tableSet.close();
			} catch (SQLException sqle) {
				String message = "Unable to close ResultSet for table list, continuing anyway... Error was:" + sqle.toString();
				log.error(message);
				throw new RuntimeException(message);
			}

		}
		return tableNames;
	}

	public boolean tableExist(String tableName) {

		DatabaseMetaData dbData = this.getDatabaseMetaData();
		if (dbData == null) {
			return false;
		}

		ResultSet tableSet = null;
		String[] types = { "TABLE" };
		String lookupSchemaName = null;
		try {
			
			lookupSchemaName = getSchemaName(dbData);
			tableSet = dbData.getTables(null, lookupSchemaName, tableName, types);
			if (tableSet == null) {
				if (dbData.storesLowerCaseIdentifiers()) {
					// 保存小写的在查询一次
					tableSet = dbData.getTables(null, lookupSchemaName, tableName.toLowerCase(), types);
				}
				if (tableSet == null) {
					log.warn("getTable:{} returned null set,SchemaName:{}", tableName,lookupSchemaName);
					return false;
				}

			}
		} catch (SQLException sqle) {
			String message = "Unable to get list of table information, let's try the create anyway... Error was:" + sqle.toString();
			log.error(message);
			throw new RuntimeException(message);

		}

		try {

			while (tableSet.next()) {
				return true;
			}
			if(dbData.storesLowerCaseIdentifiers()){
				tableSet = dbData.getTables(null, lookupSchemaName, tableName.toLowerCase(), types);
				if (tableSet == null) {
					log.warn("getTable:{} returned null set,SchemaName:{}", tableName,lookupSchemaName);
					return false;
				}else{
					while (tableSet.next()) {
						return true;
					}
					log.debug("getTable:{} returned null set,SchemaName:{}", tableName,lookupSchemaName);
					return false;
				}
				
			}else{
				log.debug("getTable:{} returned null set,SchemaName:{}", tableName,lookupSchemaName);
				return false;	
			}
			
		} catch (SQLException sqle) {
			String message = "Error getting next table information... Error was:" + sqle.toString();
			log.error(message);
			throw new RuntimeException(message);
		} finally {
			try {
				tableSet.close();
			} catch (SQLException sqle) {
				String message = "Unable to close ResultSet for table list, continuing anyway... Error was:" + sqle.toString();
				log.error(message);
				throw new RuntimeException(message);
			}

		}

	}

	public DatabaseMetaData getDatabaseMetaData() {

		DatabaseMetaData dbData = null;
		try {
			dbData = getConnection().getMetaData();
		} catch (SQLException sqle) {
			String message = "Unable to get database meta data... Error was:" + sqle.toString();
			log.error(message);
			throw new RuntimeException(message);
		}

		return dbData;
	}

	public Map<String, ColumnCheckInfo> getColumnInfo(String tableName, boolean getPks) {

		Set<String> tableNames = new HashSet<String>();
		tableNames.add(tableName);
		Map<String, Map<String, ColumnCheckInfo>> result = getColumnInfo(tableNames, getPks);
		return result.get(tableName);
	}

	public ColumnCheckInfo getColumnInfo(String tableName, boolean getPks, String columnName) {

		Set<String> tableNames = new HashSet<String>();
		tableNames.add(tableName);
		Map<String, Map<String, ColumnCheckInfo>> result = getColumnInfo(tableNames, getPks);
		Map<String, ColumnCheckInfo> table = result.get(tableName);

		return table.get(columnName);
	}

	public Map<String, Map<String, ColumnCheckInfo>> getColumnInfo(Set<String> tableNames, boolean getPks) {

		if (UtilValidate.isEmpty(tableNames)) {
			return Collections.emptyMap();
		}

		DatabaseMetaData dbData = null;
		try {
			dbData = getConnection().getMetaData();
		} catch (SQLException sqle) {
			String message = "Unable to get database meta data... Error was:" + sqle.toString();
			log.error(message);
			throw new RuntimeException(message);

		}

		Map<String, Map<String, ColumnCheckInfo>> colInfo = new HashMap<String, Map<String, ColumnCheckInfo>>();
		String lookupSchemaName;
		try {

			lookupSchemaName = getSchemaName(dbData);

			ResultSet rsCols = dbData.getColumns(null, lookupSchemaName, null, null);
			while (rsCols.next()) {
				try {
					ColumnCheckInfo ccInfo = new ColumnCheckInfo();
					String temTableName = rsCols.getString("TABLE_NAME");
					ccInfo.tableName = fixupIdentifiers(temTableName, dbData, false);
					log.debug("table name :{}  fixupTableName {}", temTableName, ccInfo.tableName);

					if (!tableNames.contains(ccInfo.tableName)) {
						continue;
					}

					ccInfo.columnName = rsCols.getString("COLUMN_NAME");

					ccInfo.columnName = fixupIdentifiers(ccInfo.columnName, dbData, false);

					// 大写?

					ccInfo.typeName = rsCols.getString("TYPE_NAME");
					ccInfo.typeNum = rsCols.getInt("DATA_TYPE");
					ccInfo.columnSize = rsCols.getInt("COLUMN_SIZE");
					ccInfo.decimalDigits = rsCols.getInt("DECIMAL_DIGITS");
					// 大写?

					ccInfo.isNullable = rsCols.getString("IS_NULLABLE");

					Map<String, ColumnCheckInfo> tableColInfo = colInfo.get(ccInfo.tableName);
					if (tableColInfo == null) {
						tableColInfo = new HashMap<String, ColumnCheckInfo>();
						colInfo.put(ccInfo.tableName, tableColInfo);
					}
					tableColInfo.put(ccInfo.columnName, ccInfo);
				} catch (SQLException sqle) {
					String message = "Error getting column info for column. Error was:" + sqle.toString();
					log.error(message);

					continue;
				}
			}

			try {
				rsCols.close();
			} catch (SQLException sqle) {
				String message = "Unable to close ResultSet for column list, Error was:" + sqle.toString();
				log.error(message);
				throw new RuntimeException(message);
			}

			if (getPks) {
				Iterator<String> tNames = tableNames.iterator();
				while (tNames.hasNext()) {
					boolean foundPk = false;
					String curentabName = fixupIdentifiers(tNames.next(), dbData, true);

					if (lookupSchemaName != null && curentabName.startsWith(lookupSchemaName.concat("."))) {
						 
							curentabName = curentabName.substring(lookupSchemaName.length() + 1);
						 

					}

					ResultSet rsPks = dbData.getPrimaryKeys(null, lookupSchemaName, curentabName);
					while (rsPks.next()) {
						foundPk = true;
						try {
							String tableName = fixupIdentifiers(rsPks.getString("TABLE_NAME"), dbData, false);
							String columnName = rsPks.getString("COLUMN_NAME");

							columnName = fixupIdentifiers(columnName, dbData, false);

							Map<String, ColumnCheckInfo> tableColInfo = colInfo.get(tableName);
							if (tableColInfo == null) {
								log.warn("not looking for info on this table:{}", tableName);
								continue;
							}
							ColumnCheckInfo ccInfo = tableColInfo.get(columnName);
							if (ccInfo == null) {

								log.warn("Got primary key information for a column that we didn't get column information for: tableName=[{}], columnName=[{}]", tableName, columnName);
								continue;
							}

							ccInfo.isPk = true;
							ccInfo.pkSeq = rsPks.getShort("KEY_SEQ");
							ccInfo.pkName = rsPks.getString("PK_NAME");
						} catch (SQLException sqle) {
							String message = "Error getting primary key info for column. Error was:" + sqle.toString();
							log.error(message);

							continue;
						}
					}

					try {
						rsPks.close();
					} catch (SQLException sqle) {
						String message = "Unable to close ResultSet for primary key list, continuing anyway... Error was:" + sqle.toString();
						log.error(message);
						throw new RuntimeException(message);
					}
					if (!foundPk) {
						log.warn("lookupSchemaName :{} ,table {} no pk", lookupSchemaName, curentabName);
					}

				}
			}
		} catch (SQLException sqle) {
			String message = "Error getting column meta data for Error was:" + sqle.toString() + ". Not checking columns.";
			log.error(message);
			throw new RuntimeException(message);

		}
		return colInfo;

	}

	/**
	 * 
	 * @param rawName
	 * @param dbData
	 * @param toDb
	 *            true 为数据库转化
	 * @return
	 * @throws SQLException
	 */
	public static String fixupIdentifiers(String rawName, DatabaseMetaData dbData, boolean toDb) throws SQLException {
		if (UtilValidate.isEmpty(rawName))
			return rawName;
		// 说明数据库修改了表名称,大写不处理
		// if (dbData.storesUpperCaseIdentifiers()) {
		// return rawTableName.toUpperCase();
		// }

		if (toDb) {
			// db使用
			if (dbData.storesLowerCaseIdentifiers()) {
				return rawName.toLowerCase();
			}
			if (dbData.storesUpperCaseIdentifiers()) {
				return rawName.toUpperCase();
			}
			return rawName;
		} else {
			// 数据库修改为小写,转为大写,程序中为大写
			if (dbData.storesLowerCaseIdentifiers() || dbData.storesMixedCaseIdentifiers()) {
				return rawName.toUpperCase();
			}
			return rawName;
		}

	}
	/**
	 * 获取索引信息
	 * @param tableNames
	 * @param messages
	 * @return key 表名称  value 索引名称
	 */
    public Map<String, Set<String>> getIndexInfo(Set<String> tableNames, Collection<String> messages) {
 

        DatabaseMetaData dbData = null;
        try {
            dbData = getDatabaseMetaData();
        } catch (Exception e) {
            String message = "Unable to get database meta data... Error was:" + e.toString();
            log.error(message);
            if (messages != null) messages.add(message);


            return null;
        }

       boolean needsUpperCase = false;
        try {
            needsUpperCase = dbData.storesLowerCaseIdentifiers() || dbData.storesMixedCaseIdentifiers();
        } catch (SQLException e) {
            String message = "Error getting identifier case information... Error was:" + e.toString();
            log.error(message);
            if (messages != null) messages.add(message);
        }

        log.info("Getting table {} Index Info From Database ,needsUpperCase {}",tableNames,needsUpperCase);

        Map<String, Set<String>> indexInfo = new HashMap<String, Set<String>>();
        try {
            int totalIndices = 0;
            String lookupSchemaName = getSchemaName(dbData);
            for (String curTableName: tableNames) {


                ResultSet rsCols = null;
                try {
                    // false for unique, we don't really use unique indexes
                    // true for approximate, don't really care if stats are up-to-date
                    rsCols = dbData.getIndexInfo(null, lookupSchemaName, needsUpperCase ? curTableName.toLowerCase() : curTableName, false, true);
                } catch (Exception e) {
                    log.warn("Error getting index info for table: {} using lookupSchemaName {}"  ,curTableName,lookupSchemaName);
                }

                while (rsCols != null && rsCols.next()) {
                    // NOTE: The code in this block may look funny, but it is designed so that the wrapping loop can be removed
                    try {
                        // skip all index info for statistics
                        if (rsCols.getShort("TYPE") == DatabaseMetaData.tableIndexStatistic) continue;

                        // HACK: for now skip all "unique" indexes since our foreign key indices are not unique, but the primary key ones are
                        // not correct, declared indices can also be unique
						// if (!rsCols.getBoolean("NON_UNIQUE")) continue;

                        String tableName = rsCols.getString("TABLE_NAME");
                        if (needsUpperCase && tableName != null) {
                            tableName = tableName.toUpperCase();
                        }

                        if (!tableNames.contains(tableName)) continue;

                        String indexName = rsCols.getString("INDEX_NAME");
                        if (needsUpperCase && indexName != null) {
                            indexName = indexName.toUpperCase();
                        }
                        if (indexName.startsWith("PK_") || indexName.startsWith("pk_")) continue;

                        Set<String> tableIndexList = indexInfo.get(tableName);
                        if (tableIndexList == null) {
                            tableIndexList = new TreeSet<String>();
                            indexInfo.put(tableName, tableIndexList);
                            log.debug("Adding new Map for table:{} " , tableName);
                        }
                        // Need the check here, because an index can contain multiple columns,
                        // and this is represented by having multiple rows in rsCols.
                        if (!tableIndexList.contains(indexName)) totalIndices++;
                        tableIndexList.add(indexName);
                    } catch (SQLException e) {
                        String message = "Error getting fk reference info for table. Error was:" + e.toString();
                        log.error(message);
                        if (messages != null) messages.add(message);
                        continue;
                    }
                }

        
                if (rsCols != null) {
                    try {
                        rsCols.close();
                    } catch (SQLException e) {
                        String message = "Unable to close ResultSet for fk reference list, continuing anyway... Error was:" + e.toString();
                        log.error(message);
                        if (messages != null) messages.add(message);
                    }
                }
            }
            log.info("There are {} indices in the database", totalIndices);

        } catch (SQLException e) {
            String message = "Error getting fk reference meta data Error was:" + e.toString() + ". Not checking fk refs.";
            log.error(message);
            if (messages != null) messages.add(message);
            indexInfo = null;
        }  
        return indexInfo;
    }
    
    
	/**
	 * 获取索引信息
	 * @param tableNames
	 * @param messages
	 * @param needsUpperCase
	 * @return key 表名称  value 索引名称 索引字段
	 */
    public Map<String, Map<String,List<String>>> getFullIndexInfo(final Set<String> tableNames, Collection<String> messages) {
 

        DatabaseMetaData dbData = null;
        try {
            dbData =   getDatabaseMetaData();
        } catch (Exception e) {
            String message = "Unable to get database meta data... Error was:" + e.toString();
            log.error(message);
            if (messages != null) messages.add(message);

            return null;
        }

        boolean needsUpperCase = false;
        try {
            needsUpperCase = dbData.storesLowerCaseIdentifiers() || dbData.storesMixedCaseIdentifiers();
        } catch (SQLException e) {
            String message = "Error getting identifier case information... Error was:" + e.toString();
            log.error(message);
            if (messages != null) messages.add(message);
        }

        log.info("Getting table {} Index Info From Database  ,needsUpperCase {} ",tableNames,needsUpperCase);

        Map<String, Map<String,List<String>>>indexInfo = new HashMap<>();
        try {
          
            String lookupSchemaName = getSchemaName(dbData);
            for (String curTableName: tableNames) {


                ResultSet rsCols = null;
                try {

                    rsCols = dbData.getIndexInfo(null, lookupSchemaName, needsUpperCase ? curTableName.toLowerCase() : curTableName, false, true);
                } catch (Exception e) {
                    log.warn("Error getting index info for table: {} using lookupSchemaName {}"  ,curTableName,lookupSchemaName);
                }

                while (rsCols != null && rsCols.next()) {
                 
                    try {
                        // skip all index info for statistics
                        if (rsCols.getShort("TYPE") == DatabaseMetaData.tableIndexStatistic) continue;


                        String tableName = rsCols.getString("TABLE_NAME");
                        if (needsUpperCase && tableName != null) {
                            tableName = tableName.toUpperCase();
                        }

                        if (!tableNames.contains(tableName)) continue;

                        String indexName = rsCols.getString("INDEX_NAME");
                        if (needsUpperCase && indexName != null) {
                            indexName = indexName.toUpperCase();
                        }

                        Map<String,List<String>> tableIndexList = indexInfo.get(tableName);
                        if (tableIndexList == null) {
                            tableIndexList = new HashMap<String,List<String>>();
                            indexInfo.put(tableName, tableIndexList);
                            log.debug("Adding new Map for table:{} " , tableName);
                        }
                        List<String> inxCol=tableIndexList.get(indexName);
                        if(inxCol==null){
                        	inxCol=new ArrayList<>();
                        	tableIndexList.put(indexName,inxCol);
                        }
                        String indexColName = rsCols.getString("COLUMN_NAME");
                        if(UtilValidate.isNotEmpty(indexColName)){
                        	inxCol.add(indexColName);
                        }
                        
                    } catch (SQLException e) {
                        String message = "Error getting fk reference info for table. Error was:" + e.toString();
                        log.error(message);
                        if (messages != null) messages.add(message);
                        continue;
                    }
                }

          
                if (rsCols != null) {
                    try {
                        rsCols.close();
                    } catch (SQLException e) {
                        String message = "Unable to close ResultSet for fk reference list, continuing anyway... Error was:" + e.toString();
                        log.error(message);
                        if (messages != null) messages.add(message);
                    }
                }
            }
 

        } catch (SQLException e) {
            String message = "Error getting fk reference meta data Error was:" + e.toString() + ". Not checking fk refs.";
            log.error(message);
            if (messages != null) messages.add(message);
            indexInfo = null;
        } 
        return indexInfo;
    }
	public static class ColumnCheckInfo implements Serializable {
		public String tableName;

		public String columnName;

		public String typeName;

		public int typeNum;

		public int columnSize;

		public int decimalDigits;

		public String isNullable; // YES/NO or "" = 未知

		public boolean isPk = false;

		public int pkSeq;

		public String pkName;

		public String toString() {
			StringBuilder result = new StringBuilder(512);
			result.append("tableName=");
			result.append(tableName);
			result.append("\n");

			result.append("columnName=");
			result.append(columnName);
			result.append("\n");

			result.append("typeName=");
			result.append(typeName);
			result.append("\n");

			result.append("columnSize=");
			result.append(columnSize);
			result.append("\n");

			result.append("decimalDigits=");
			result.append(decimalDigits);
			result.append("\n");

			result.append("isNullable=");
			result.append(isNullable);
			result.append("\n");

			result.append("isPk=");
			result.append(isPk);
			result.append("\n");

			result.append("pkSeq=");
			result.append(pkSeq);
			result.append("\n");

			result.append("pkName=");
			result.append(pkName);
			result.append("\n");
			return result.toString();
		}
	}

	public Connection getConnection() {
		return connection;
	}

	public void setConnection(Connection connection) {
		this.connection = connection;
	}

}
